/*
 This file is part of the OdinMS Maple Story Server
 Copyright (C) 2008 ~ 2010 Patrick Huy <patrick.huy@frz.cc> 
 Matthias Butz <matze@odinms.de>
 Jan Christian Meyer <vimes@odinms.de>

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License version 3
 as published by the Free Software Foundation. You may not use, modify
 or distribute this program under any other version of the
 GNU Affero General Public License.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.

 You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package handling.channel.handler;

import java.util.List;
import java.util.ArrayList;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import client.inventory.Item;
import client.inventory.MapleInventoryType;
import client.MapleClient;
import client.MapleCharacter;
import constants.GameConstants;
import client.inventory.ItemLoader;
import constants.ServerConfig;
import constants.ServerConstants;
import database.DBConPool;
import handling.world.World;
import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import server.MapleInventoryManipulator;
import server.MapleItemInformationProvider;
import server.MerchItemPackage;
import server.maps.MapleMap;
import tools.FileoutputUtil;
import tools.Pair;
import tools.StringUtil;
import tools.packet.PlayerShopPacket;
import tools.data.LittleEndianAccessor;
import tools.packet.CField.NPCPacket;
import tools.packet.CWvsContext;

public class HiredMerchantHandler {


    public static final boolean UseHiredMerchant(final MapleClient c, final boolean packet) {
        if (ServerConfig.Hiredbusinessman) {
            if (c.getPlayer().getMap() != null && c.getPlayer().getMap().allowPersonalShop()) {
            final byte state = checkExistance(c.getPlayer().getAccountID(), c.getPlayer().getId());

            switch (state) {
                case 1:
                    c.getPlayer().dropMessage(1, "请先去找弗兰德里领取你的东西。");
                    break;
                case 0:
                    boolean merch = World.hasMerchant(c.getPlayer().getAccountID(), c.getPlayer().getId());
                    if (!merch) {
                        if (c.getChannelServer().isShutdown()) {
                            c.getPlayer().dropMessage(1, "服务器即将关闭，不能执行此操作。");
                            return false;
                        }
                        if (packet) {
                            c.getSession().write(PlayerShopPacket.sendTitleBox());
                        }
                        return true;
                    } else {
                        c.getSession().write(PlayerShopPacket.ShowMerchItemStore(9030000, World.getMerchantMap(c.getPlayer()), World.getMerchantChannel(c.getPlayer())));
                    }
                    break;
                default:
                    c.getPlayer().dropMessage(1, "发生未知错误.");
                    break;
            }
        } else {
            c.getSession().close();
        }
        } else {
            c.getPlayer().dropMessage(1, "管理员已经从后台关闭了雇佣商人功能");
        }
        return false;
    }
    
    private static byte checkExistance(final int accid, final int cid) {
        try (Connection con = DBConPool.getInstance().getDataSource().getConnection()) {
            try (PreparedStatement ps = con.prepareStatement("SELECT * from hiredmerch where accountid = ? OR characterid = ?")) {
                ps.setInt(1, accid);
                ps.setInt(2, cid);
                try (ResultSet rs = ps.executeQuery()) {
                    if (rs.next()) {
                        ps.close();
                        rs.close();
                        return 1;
                    }
                }
            }
            return 0;
        } catch (SQLException ex) {
            FileoutputUtil.outputFileError(FileoutputUtil.MysqlEx_Log, ex);
            System.err.println(ex);

            return -1;
        }
    }

    public static void displayMerch(MapleClient c) {
        final int conv = c.getPlayer().getConversation();
        boolean merch = World.hasMerchant(c.getPlayer().getAccountID(), c.getPlayer().getId());
        if (merch) {
            c.getSession().write(PlayerShopPacket.ShowMerchItemStore(9030000, World.getMerchantMap(c.getPlayer()), World.getMerchantChannel(c.getPlayer())));
            c.getPlayer().setConversation(0);
        } else if (c.getChannelServer().isShutdown()) {
            c.getPlayer().dropMessage(1, "服务器即将关闭，不能执行此操作。");
            c.getPlayer().setConversation(0);
        } else if (conv == 3) { // Hired Merch
            final MerchItemPackage pack = loadItemFrom_Database(c.getPlayer().getAccountID());

            if (pack == null) {
                c.getSession().write(PlayerShopPacket.merchItemStore((byte) 0x25, 0, 0));
                c.getPlayer().setConversation(0);
            } else if (pack.getItems().size() <= 0) { //error fix for complainers.
                if (!check(c.getPlayer(), pack)) {
                    c.getSession().write(PlayerShopPacket.merchItem_Message((byte) 0x21));
                    return;
                }
                if (deletePackage(c.getPlayer().getAccountID(), pack.getPackageid(), c.getPlayer().getId())) {
                    //c.getPlayer().fakeRelog();
                    //c.getPlayer().gainMeso(pack.getMesos(), false);
                    c.getSession().write(PlayerShopPacket.merchItem_Message((byte) 0x1d));
                    c.getPlayer().setConversation(0);
                } else {
                    c.getPlayer().dropMessage(1, "发生未知错误");
                }
                c.getPlayer().setConversation(0);
            } else {
                c.getSession().write(PlayerShopPacket.merchItemStore_ItemData(pack));
                MapleInventoryManipulator.checkSpace(c, conv, conv, null);
                for (final Item item : pack.getItems()) {
                    if (c.getPlayer().getInventory(GameConstants.getInventoryType(item.getItemId())).isFull()) {
                        c.getSession().write(NPCPacket.getNPCTalk(9030000, (byte) 0, "Please clean up your inventory.", "00 00", (byte) 0));
                        c.getPlayer().setConversation(0);
                        break;
                    }
                    MapleInventoryManipulator.addFromDrop(c, item, true);
                    deletePackage(c.getPlayer().getAccountID(), pack.getPackageid(), c.getPlayer().getId());
                    //c.getPlayer().fakeRelog();
                    c.getSession().write(NPCPacket.getNPCTalk(9030000, (byte) 0, "您雇佣商店保存的道具已发送到背包上.", "00 00", (byte) 0));
                    c.getPlayer().setConversation(0);
                }

            }
        }
        c.getSession().write(CWvsContext.enableActions());
    }

    public static final void MerchantItemStore(final LittleEndianAccessor slea, final MapleClient c) {
        if (c.getPlayer() == null) {
            return;
        }
        final byte operation = slea.readByte();
        switch (operation) {
            case 20: {
                final int conv = c.getPlayer().getConversation();
                final int HMMap = MapleMap.getMerchantMap(c.getPlayer());
                final int HMChannel = MapleMap.getMerchantChannel(c.getPlayer());
                boolean merch = World.hasMerchant(c.getPlayer().getAccountID(), c.getPlayer().getId());
                if (merch) {
                    c.getSession().write(PlayerShopPacket.ShowMerchItemStore(9030000, HMMap, HMChannel));
                    c.getPlayer().setConversation(0);
                } else if (c.getChannelServer().isShutdown()) {
                    c.getPlayer().dropMessage(1, "服务器即将关闭，不能执行此操作。");
                    c.getPlayer().setConversation(0);
                } else if (conv == 3) { // Hired Merch
                    final MerchItemPackage pack = loadItemFrom_Database(c.getPlayer().getAccountID());

                    if (pack == null) {
                        c.getSession().write(PlayerShopPacket.merchItemStore((byte) 0x25, 0, 0));
                        c.getPlayer().setConversation(0);
                    } else if (c.getPlayer().getMeso() + pack.getMesos() >= 2147483647) {
                        c.getPlayer().dropMessage(1, "您的钱领取后将会过多，请先将多余的钱放到仓库！");
                        c.getPlayer().setConversation(0);
                    } else if (c.getPlayer().getMeso() + pack.getMesos() <= 0) {
                        c.getPlayer().dropMessage(1, "您身上没有钱，无法领取！");
                        c.getPlayer().setConversation(0);
                    } else if (pack.getItems().size() <= 0) { //error fix for complainers.
                        if (!check(c.getPlayer(), pack)) {
                            c.getSession().write(PlayerShopPacket.merchItem_Message((byte) 0x21));
                            return;
                        }
                        if (deletePackage(c.getPlayer().getAccountID(), pack.getPackageid(), c.getPlayer().getId())) {

                            c.getPlayer().gainMeso(pack.getMesos(), true);
                            c.getPlayer().dropMessage(1, "你从雇佣商人领取了" + pack.getMesos() + "金币");
                            //c.getSession().write(PlayerShopPacket.merchItem_Message((byte) 0x1d));
                            c.getPlayer().setConversation(0);
                            if (ServerConfig.logs_mrechant) {
                                FileoutputUtil.logToFile("logs/玩家操作/雇佣商人领回.txt", FileoutputUtil.NowTime() + " 账号: " + c.getAccountName() + " 玩家: " + c.getPlayer().getName() + " 从雇佣商人领回金币: " + pack.getMesos() + "]\r\n");
                            }
                        } else {
                            c.getPlayer().dropMessage(1, "发生未知错误。");
                        }
                        c.getPlayer().setConversation(0);
                    } else {
                        c.getSession().write(PlayerShopPacket.merchItemStore_ItemData(pack));

                        /*MapleInventoryManipulator.checkSpace(c, conv, conv, null);
                        for (final Item item : pack.getItems()) {
                            if (c.getPlayer().getInventory(GameConstants.getInventoryType(item.getItemId())).isFull()) {
                                c.getSession().write(NPCPacket.getNPCTalk(9030000, (byte) 0, "请检查你的背包是否已满。", "00 00", (byte) 0));
                                c.getPlayer().setConversation(0);
                                break;
                            }
                            MapleInventoryManipulator.addFromDrop(c, item, true);
                            deletePackage(c.getPlayer().getAccountID(), pack.getPackageid(), c.getPlayer().getId());
                            c.getSession().write(NPCPacket.getNPCTalk(9030000, (byte) 0, "请检查你的背包是否已满。", "00 00", (byte) 0));
                            c.getPlayer().setConversation(0);
                        }*/
                    }
                }

                break;
            }
            case 25: { // 要求拿出物品
                if (c.getPlayer().getConversation() != 3) {
                    return;
                }
                c.getSession().write(PlayerShopPacket.merchItemStore((byte) 0x24, 0, 0));// 38
                break;
            }
            case 26: { // 取出物品
                if (c.getPlayer().getConversation() != 3) {
                    c.getPlayer().dropMessage(1, "发生未知错误.");
                    c.getSession().write(CWvsContext.enableActions());
                    return;
                }
                final MerchItemPackage pack = loadItemFrom_Database(c.getPlayer().getAccountID());

                if (pack == null) {
                    c.getSession().write(PlayerShopPacket.merchItemStore((byte) 0x25, 0, 0));
                    return;
                }

                if (!check(c.getPlayer(), pack)) {
                    c.getSession().write(PlayerShopPacket.merchItem_Message((byte) 0x21));
                    return;
                }
                if (c.getPlayer().getMeso() + pack.getMesos() >= 2147483647) {
                    c.getPlayer().dropMessage(1, "您的钱领取后将会过多，请先将多余的钱放到仓库！");
                    c.getPlayer().setConversation(0);
                }
                if (c.getPlayer().getMeso() + pack.getMesos() <= 0) {
                    c.getPlayer().dropMessage(1, "您身上没有钱，无法领取！");
                    c.getPlayer().setConversation(0);
                }
                if (deletePackage(c.getPlayer().getAccountID(), pack.getPackageid(), c.getPlayer().getId())) {
                    c.getPlayer().gainMeso(pack.getMesos(), false);
                    for (Item item : pack.getItems()) {
                        MapleInventoryManipulator.addFromDrop(c, item, false);
                    }
                    c.getSession().write(PlayerShopPacket.merchItem_Message((byte) 0x1d));

                    c.getPlayer().setConversation(0);
                    String output = "";
                    for (Item item : pack.getItems()) {
                        output += item.getItemId() + "(" + item.getQuantity() + "), ";
                    }

                    if (ServerConfig.logs_mrechant) {
                        FileoutputUtil.logToFile("logs/玩家操作/雇佣商人领回.txt", FileoutputUtil.NowTime() + " 账号: " + c.getAccountName() + " 玩家: " + c.getPlayer().getName() + " 从雇佣商人领回金币: " + pack.getMesos() + " 和" + pack.getItems().size() + "件物品[" + output + "]\r\n");
                    }

                } else {
                    c.getPlayer().dropMessage(1, "发生未知错误.");
                }
                break;
            }
            case 27: { // Exit
                c.getPlayer().setConversation(0);
                break;
            }
        }
        /*if (operation == 27 || operation == 28) { // Request, Take out
            requestItems(c, operation == 27);
        } else if (operation == 30) { // Exit
            c.getPlayer().setConversation(0);
        }*/
    }

    private static void requestItems(final MapleClient c, final boolean request) {
        if (c.getPlayer().getConversation() != 3) {
            return;
        }
        boolean merch = World.hasMerchant(c.getPlayer().getAccountID(), c.getPlayer().getId());
        if (merch) {
            c.getPlayer().dropMessage(1, "请关闭雇用后再试一次");
            c.getPlayer().setConversation(0);
            return;
        }
        final MerchItemPackage pack = loadItemFrom_Database(c.getPlayer().getAccountID());
        if (pack == null) {
            c.getPlayer().dropMessage(1, "发生未知的错误.");
            return;
        } else if (c.getChannelServer().isShutdown()) {
            c.getPlayer().dropMessage(1, "服务器即将关闭，不能执行此操作。.");
            c.getPlayer().setConversation(0);
            return;
        }
        final int days = StringUtil.getDaysAmount(pack.getSavedTime(), System.currentTimeMillis()); // max 100%
        final double percentage = days / 100.0;
        final int fee = (int) Math.ceil(percentage * pack.getMesos()); // if no mesos = no tax
        if (request && days > 0 && percentage > 0 && pack.getMesos() > 0 && fee > 0) {
            c.getSession().write(PlayerShopPacket.merchItemStore((byte) 38, days, fee));
            return;
        }
        if (fee < 0) { // impossible
            c.getSession().write(PlayerShopPacket.merchItem_Message(33));
            return;
        }
        if (c.getPlayer().getMeso() < fee) {
            c.getSession().write(PlayerShopPacket.merchItem_Message(35));
            return;
        }
        if (!check(c.getPlayer(), pack)) {
            c.getSession().write(PlayerShopPacket.merchItem_Message(36));
            return;
        }
        if (deletePackage(c.getPlayer().getAccountID(), pack.getPackageid(), c.getPlayer().getId())) {
            if (fee > 0) {
                c.getPlayer().gainMeso(-fee, true);
            }
            c.getPlayer().gainMeso(pack.getMesos(), false);
            for (Item item : pack.getItems()) {
                MapleInventoryManipulator.addFromDrop(c, item, false);
            }
            c.getSession().write(PlayerShopPacket.merchItem_Message(32));
        } else {
            c.getPlayer().dropMessage(1, "发生未知的错误.");
        }
    }

    private static boolean check(final MapleCharacter chr, final MerchItemPackage pack) {
        if (chr.getMeso() + pack.getMesos() < 0) {
            return false;
        }
        byte eq = 0, use = 0, setup = 0, etc = 0, cash = 0;
        for (Item item : pack.getItems()) {
            final MapleInventoryType invtype = GameConstants.getInventoryType(item.getItemId());
            if (invtype == MapleInventoryType.EQUIP) {
                eq++;
            } else if (invtype == MapleInventoryType.USE) {
                use++;
            } else if (invtype == MapleInventoryType.SETUP) {
                setup++;
            } else if (invtype == MapleInventoryType.ETC) {
                etc++;
            } else if (invtype == MapleInventoryType.CASH) {
                cash++;
            }
            if (MapleItemInformationProvider.getInstance().isPickupRestricted(item.getItemId()) && chr.haveItem(item.getItemId(), 1)) {
                return false;
            }
        }
        return chr.getInventory(MapleInventoryType.EQUIP).getNumFreeSlot() >= eq && chr.getInventory(MapleInventoryType.USE).getNumFreeSlot() >= use && chr.getInventory(MapleInventoryType.SETUP).getNumFreeSlot() >= setup && chr.getInventory(MapleInventoryType.ETC).getNumFreeSlot() >= etc && chr.getInventory(MapleInventoryType.CASH).getNumFreeSlot() >= cash;
    }

    private static boolean deletePackage(final int accid, final int packageid, final int chrId) {
        try (Connection con = DBConPool.getInstance().getDataSource().getConnection()) {
            try (PreparedStatement ps = con.prepareStatement("DELETE from hiredmerch where accountid = ? OR packageid = ? OR characterid = ?")) {
                ps.setInt(1, accid);
                ps.setInt(2, packageid);
                ps.setInt(3, chrId);
                ps.executeUpdate();
            }
            ItemLoader.HIRED_MERCHANT.saveItems(null, packageid);
            return true;
        } catch (SQLException ex) {
            FileoutputUtil.outputFileError(FileoutputUtil.MysqlEx_Log, ex);
            System.err.println(ex);
            return false;
        }
    }

    public static final void showFredrick(MapleClient c) {
        final MerchItemPackage pack = HiredMerchantHandler.loadItemFrom_Database(c.getPlayer().getAccountID());
        c.getSession().write(PlayerShopPacket.merchItemStore_ItemData(pack));
    }

    private static MerchItemPackage loadItemFrom_Database(final int accountid) {
        try (Connection con = DBConPool.getInstance().getDataSource().getConnection()) {
            ResultSet rs;

            final int packageid;
            final MerchItemPackage pack;
            try (PreparedStatement ps = con.prepareStatement("SELECT * from hiredmerch where accountid = ?")) {
                ps.setInt(1, accountid);
                rs = ps.executeQuery();
                if (!rs.next()) {
                    ps.close();
                    rs.close();
                    return null;
                }
                packageid = rs.getInt("PackageId");
                pack = new MerchItemPackage();
                pack.setPackageid(packageid);
                pack.setMesos(rs.getInt("Mesos"));
                pack.setSavedTime(rs.getLong("time"));
            }
            rs.close();

            Map<Long, Pair<Item, MapleInventoryType>> items = ItemLoader.HIRED_MERCHANT.loadItems(false, packageid);
            if (items != null) {
                List<Item> iters = new ArrayList<>();
                for (Pair<Item, MapleInventoryType> z : items.values()) {
                    iters.add(z.left);
                }
                pack.setItems(iters);
            }

            return pack;
        } catch (SQLException ex) {
            FileoutputUtil.outputFileError(FileoutputUtil.MysqlEx_Log, ex);
            System.err.println(ex);
            return null;
        }
    }

    private HiredMerchantHandler() {
    }
}
